﻿using System;
using System.Disposables;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using SoftSource.Common;
using SoftSource.MVVMC;
using SoftSource.Reactive;
using SoftSource.Timecard.Resources;
using SoftSource.Timecard.ViewModelInterfaces;
using SoftSource.Timecard.Web.Data;

namespace SoftSource.Timecard.Views
{
    public sealed partial class ProjectListView : UserControl, IView<IProjectListViewModelConsume>, IDisposable
    {
        #region Fields
        private CompositeDisposable compositeDisposable;
        private Filter<ProjectSummary> filter;
        private string nameFilter;
        private Predicate<ProjectSummary> checkBoxFilter;
        private bool isEditorOpen;
        #endregion Fields

        public ProjectListView()
        {
            InitializeComponent();

            Loaded += new RoutedEventHandler(ProjectListView_Loaded);

            this.isEditorOpen = false;
            this.compositeDisposable = new CompositeDisposable();

        }

        #region Events
        void ProjectListView_Loaded(object sender, RoutedEventArgs e)
        {
            if (this.ViewModel != null)
            {
                this.Busy.BusyContent = ApplicationStrings.LoadingMessage;
                this.Busy.IsBusy = true;

                this.ViewModel.Load // Load the data required to use this ViewModel
                    .Nullable()
                    .Subscribe(unit =>
                        {
                            this.Busy.IsBusy = false;
                            this.filter = this.ViewModel.Projects.AttachFilter<ProjectSummary>();
                            this.AttatchFilters();
                            this.RunFilters();
                        });


                this.ViewModel.PropertyChanged += (sender2, e2) =>
                    {
                        if (e2.PropertyName == "Projects")
                            this.RunFilters();
                    };

                var throttledFilterDisposable = Observable.FromEvent<TextChangedEventHandler, TextChangedEventArgs>(
                    handler => (sender2, e2) => handler(sender2, e2),
                    handler => this.FilterTextBox.TextChanged += handler,
                    handler => this.FilterTextBox.TextChanged -= handler)
                    .Throttle(TimeSpan.FromSeconds(0.2))
                    .Subscribe(args =>
                    {
                        this.nameFilter = this.FilterTextBox.Text.ToLower();
                        this.RunFilters();
                    });
                
                var beginningEditDisposable = this.ProjectDataGrid
                    .WhenBeginningEdit()
                    .Subscribe(args =>
                        {
                            args.EventArgs.Cancel = true;
                            var summary = args.EventArgs.Row.DataContext as ProjectSummary;

                            if (summary != null)
                            {
                                Func<Action, UIElement> editorCreator = completed => this.ViewModel.CreateProjectEditor.TryInvoke(summary.ProjectID, completed);
                                this.OpenEditor(editorCreator);
                            }
                        });

                this.compositeDisposable.Add(beginningEditDisposable);
                this.compositeDisposable.Add(throttledFilterDisposable);
            }
        }

        private void CheckBoxFilter_CheckChanged(object sender, RoutedEventArgs e)
        {
            this.RunFilters();
        }

        private void AddNew_Click(object sender, RoutedEventArgs e)
        {
            this.OpenEditor(this.ViewModel.CreateNewProjectEditor);
        }

        private void Clone_Click(object sender, RoutedEventArgs e)
        {
            var summary = this.ProjectDataGrid.SelectedItem as ProjectSummary;

            if (summary != null)
            {
                Func<Action, UIElement> editorCreator = completed => this.ViewModel.CreateCloneProjectEditor.TryInvoke(summary.ProjectID, completed);
                this.OpenEditor(editorCreator);
            }
        }
        #endregion Events

        #region Methods

        private void OpenEditor(Func<Action, UIElement> editorCreator)
        {
            if (!this.isEditorOpen)
            {
                ChildWindow cw = new ChildWindow();
                cw.HasCloseButton = false;
                cw.Title = "Edit Project";

                UIElement editor = editorCreator.TryInvoke(cw.Close);

                cw.Closed += (sender, e) => this.isEditorOpen = false;

                cw.Content = editor;
                cw.Show();
                this.isEditorOpen = true;
            }
        }

        private void RunFilters()
        {
            if (this.ViewModel != null)
            {
                this.filter.Refresh.TryInvoke();
            }
        }

        private void AttatchFilters()
        {
            this.filter.Add(summary =>
                {
                    if (string.IsNullOrEmpty(this.nameFilter))
                        return true;

                    return summary.Name.ToLower().Contains(this.nameFilter);
                });

            this.checkBoxFilter = summary =>
                {
                    int status = summary.StatusID;
                    bool include = false;

                    switch (status)
                    {
                        case ProjectStatus.Active:
                            if (this.ActiveCheckBox.IsChecked ?? false)
                                include = true;
                            break;
                        case ProjectStatus.Completed:
                            if (this.CompletedCheckBox.IsChecked ?? false)
                                include = true;
                            break;
                        case ProjectStatus.Suspended:
                            if (this.SuspendedCheckBox.IsChecked ?? false)
                                include = true;
                            break;
                        case ProjectStatus.Delayed:
                            if (this.DelayedCheckBox.IsChecked ?? false)
                                include = true;
                            break;
                        case ProjectStatus.NotStarted:
                            if (this.NotStartedCheckBox.IsChecked ?? false)
                                include = true;
                            break;
                        default:
                            include = false;
                            break;
                    }

                    return include;
                };

            this.filter.Add(summary => this.checkBoxFilter(summary));
        }
        #endregion Methods

        #region IView<IProjectListViewModel> Members

        public IProjectListViewModelConsume ViewModel
        {
            get { return this.DataContext as IProjectListViewModelConsume; }
            set { this.DataContext = value; }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            this.compositeDisposable.Dispose();
        }

        #endregion
    }
}
